//****************************************Copyright (c)***********************************//
//原子哥在线教学平台：www.yuanzige.com
//技术支持：www.openedv.com
//淘宝店铺：http://openedv.taobao.com 
//关注微信公众平台微信号："正点原子"，免费获取ZYNQ & FPGA & STM32 & LINUX资料。
//版权所有，盗版必究。
//Copyright(C) 正点原子 2018-2028
//All rights reserved	                               
//----------------------------------------------------------------------------------------
// File name:           uart_tx
// Last modified Date:  2022/7/11 14:35:36
// Last Version:        V1.1
// Descriptions:        uart_demo串口发送模块
//----------------------------------------------------------------------------------------
// Created by:          正点原子
// Created date:        2022/7/11 10:20:36
// Version:             V1.0
// Descriptions:        The original version
//
//----------------------------------------------------------------------------------------
//****************************************************************************************//

module uart_tx(
	input					sys_clk,        //系统时钟
	input					sys_rst_n,      //复位，低电平有效
	
	input		[7:0]		txd_data,       //发送的数据
	input					tx_done,        //发送完成的信号
        
	output	reg				uart_tx         //发送端
);

//reg define
reg					tx_done_d0;             //发送寄存器1
reg					tx_done_d1;             //发送寄存器2
reg					tx_flag;                //发送数据标志位
reg     [3:0]		tx_cnt;                 //发送bit计数
reg	    [15:0]		baud_cnt;               //波特率计数器
reg	    [7:0]		tx_data;                //发送的数据

//wire define
wire	tx_start;                           //发送信号开始

//*****************************************************
//**                    main code
//*****************************************************
//在串口发送过程中给出开始信号标志
assign tx_start = tx_done_d0 & (~tx_done_d1);

//对发送完成信号延迟两个时钟周期消除亚稳态
always @ (posedge sys_clk or negedge sys_rst_n) begin
	if(!sys_rst_n) begin
		tx_done_d0 <= 1'b0;
		tx_done_d1 <= 1'b0;
	end
	else begin
		tx_done_d0 <= tx_done;
		tx_done_d1 <= tx_done_d0;
	end
end

//当脉冲信号发送信号开始，进入发送状态
always @ (posedge sys_clk or negedge sys_rst_n) begin
	if(!sys_rst_n) 
		tx_flag <= 1'b0;
	else
		if(tx_start)                                                    //进入发送开始
			tx_flag <= 1'b1;                                            //发送标志拉高
		else if(tx_cnt == 4'd9 && baud_cnt == (26'd25_000_000 / 17'd115_200 - 1'b1))
			tx_flag <= 1'b0;                                            //停止发送过程
end

//进入发送过程，启动波特率计数器
always @ (posedge sys_clk or negedge sys_rst_n) begin
	if(!sys_rst_n)
		baud_cnt <= 16'd0;
	else if(tx_flag) begin                                              //处于发送过程
		if(baud_cnt < (26'd50_000_000 / 17'd115_200 - 1'b1))
			baud_cnt <= baud_cnt + 1'b1;
		else
			baud_cnt <= 16'd0;                                          //进行清零
    end            
	else
		baud_cnt <= 16'd0;                                              //发送过程结束
end

//进入发送过程，启动对应bit数据的计数
always @(posedge sys_clk or negedge sys_rst_n) begin
	if(!sys_rst_n)
		tx_cnt <= 4'd0;
	else if(tx_flag) begin                                              //处于发送过程
		if(baud_cnt == (26'd50_000_000 / 17'd115_200 - 1'b1))                                  //对于系统时钟计数达到一个周期
			tx_cnt <= tx_cnt + 1'b1;                                    //进行数据位累加
		else
			tx_cnt <= tx_cnt;
	end
	else
		tx_cnt <= 4'd0;                                                 //发送结束
end

//当脉冲检测到发送开始信号将发送的数据发送给发送寄存器中
always @ (posedge sys_clk or negedge sys_rst_n) begin
	if(!sys_rst_n)
		tx_data <= 8'd0;
	else if(tx_start)
		tx_data <= txd_data;
	else 
		tx_data <= tx_data;
end

//根据发送数据计数器来给uart发送端口赋值
always @ (posedge sys_clk or negedge sys_rst_n) begin
	if(!sys_rst_n) begin
		uart_tx <= 1'd1;
	end
	else if(tx_flag && (baud_cnt == 16'd0)) begin                       //发送信号有效且计数为起始位
			case(tx_cnt)                                                //发送端的比特计数器
				4'd0: uart_tx <= 1'b0;                                  //数据最低位
				4'd1: uart_tx <= tx_data[0];
				4'd2: uart_tx <= tx_data[1];
				4'd3: uart_tx <= tx_data[2];
				4'd4: uart_tx <= tx_data[3];
				4'd5: uart_tx <= tx_data[4];
				4'd6: uart_tx <= tx_data[5];
				4'd7: uart_tx <= tx_data[6];
				4'd8: uart_tx <= tx_data[7];                              //数据最高位
				4'd9: uart_tx <= 1'b1;                                    //停止位
			endcase
	end
end

endmodule
